﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;

namespace SweetSQL.Data
{
    internal static class SqlLanguage
    {
        private static class Syntax
        {
            public const string INSERT = "INSERT INTO ",
                UPDATE = "UPDATE ",
                SELECT = "SELECT ",
                DELETE = "DELETE FROM ",
                CREATE_TABLE = "CREATE TABLE ",
                //IF_NOT_EXISTS = "IF NOT EXISTS ",
                IF_EXISTS = "IF EXISTS ",
                DROP_TABLE = "DROP TABLE ",
                VALUES = ")VALUES(",
                COMMA = ",",
                EQUALS = " = ",
                SET = " SET ",
                FROM = " FROM ",
                WHERE = " WHERE ",
                AND = " AND ";
        }

        public static string BuildSelect<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            int length = tableInfo.Columns.Count;
            Util.ThrowIf<T>(length == 0, ErrorMessages.NO_COLUMNS);
            StringBuilder builder = new StringBuilder(Syntax.SELECT);
            for (int i = 0; i < length; i++)
            {
                provider.AppendColumn(builder, tableInfo.Columns[i]);
                if (i != length - 1)
                {
                    builder.Append(Syntax.COMMA);
                }
            }
            builder.Append(Syntax.FROM);
            provider.AppendTable(builder, tableInfo);
            return builder.ToString();
        }

        public static string BuildSelectOne<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            int length = tableInfo.Columns.Count,
                pkeyCount = tableInfo.PrimaryKeys.Count;
            Util.ThrowIf<T>(length == 0, ErrorMessages.NO_COLUMNS);
            Util.ThrowIf<T>(pkeyCount == 0, ErrorMessages.NO_PKEY);
            StringBuilder builder = new StringBuilder(Syntax.SELECT);
            for (int i = 0; i < length; i++)
            {
                provider.AppendColumn(builder, tableInfo.Columns[i]);
                if (i != length - 1)
                {
                    builder.Append(Syntax.COMMA);
                }
            }
            builder.Append(Syntax.FROM);
            provider.AppendTable(builder, tableInfo);
            builder.Append(Syntax.WHERE);
            for (int i = 0; i < pkeyCount; i++)
            {
                provider.AppendColumn(builder, tableInfo.PrimaryKeys[i]);
                builder.Append(Syntax.EQUALS);
                builder.Append(provider.CreateParameterName(i));
                if (i != pkeyCount - 1)
                {
                    builder.Append(Syntax.AND);
                }
            }
            return builder.ToString();
        }

        public static string BuildInsert<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            int length = tableInfo.Columns.Count;
            Util.ThrowIf<T>(length == 0, ErrorMessages.NO_COLUMNS);
            StringBuilder builder = new StringBuilder(Syntax.INSERT);
            provider.AppendTable(builder, tableInfo);
            builder.Append(" (");
            for (int i = 0; i < length; i++)
            {
                provider.AppendColumn(builder, tableInfo.Columns[i]);
                if (i != length - 1)
                {
                    builder.Append(Syntax.COMMA);
                }
            }
            builder.Append(Syntax.VALUES);
            for (int i = 0; i < length; i++)
            {
                builder.Append(provider.CreateParameterName(i));
                if (i != length - 1)
                {
                    builder.Append(Syntax.COMMA);
                }
            }
            builder.Append(')');
            return builder.ToString();
        }

        public static string BuildUpdate<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            int length = tableInfo.Columns.Count,
                pkeyCount = tableInfo.PrimaryKeys.Count;
            Util.ThrowIf<T>(length == 0, ErrorMessages.NO_COLUMNS);
            Util.ThrowIf<T>(pkeyCount == 0, ErrorMessages.NO_PKEY);
            StringBuilder builder = new StringBuilder(Syntax.UPDATE);
            provider.AppendTable(builder, tableInfo);
            builder.Append(Syntax.SET);
            for (int i = 0; i < length; i++)
            {
                provider.AppendColumn(builder, tableInfo.Columns[i]);
                builder.Append(Syntax.EQUALS);
                builder.Append(provider.CreateParameterName(i));
                if (i != length - 1)
                {
                    builder.Append(Syntax.COMMA);
                }
            }
            builder.Append(Syntax.WHERE);
            for (int i = 0; i < pkeyCount; i++)
            {
                provider.AppendColumn(builder, tableInfo.PrimaryKeys[i]);
                builder.Append(Syntax.EQUALS);
                builder.Append(provider.CreateParameterName(length + i));

                if (i != pkeyCount - 1)
                {
                    builder.Append(Syntax.AND);
                }
            }
            return builder.ToString();
        }

        public static string BuildDelete<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            StringBuilder builder = new StringBuilder(Syntax.DELETE);
            provider.AppendTable(builder, tableInfo);
            return builder.ToString();
        }

        public static string BuildDeleteOne<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            int length = tableInfo.PrimaryKeys.Count;
            Util.ThrowIf<T>(length == 0, ErrorMessages.NO_PKEY);
            StringBuilder builder = new StringBuilder(Syntax.DELETE);
            provider.AppendTable(builder, tableInfo);
            builder.Append(Syntax.WHERE);
            for (int i = 0; i < length; i++)
            {
                provider.AppendColumn(builder, tableInfo.PrimaryKeys[i]);
                builder.Append(Syntax.EQUALS);
                builder.Append(provider.CreateParameterName(i));
                if (i != length - 1)
                {
                    builder.Append(Syntax.AND);
                }
            }
            return builder.ToString();
        }

        public static string BuildCreateTable<T>(ISyntaxProvider syntaxProvider, TableInfo tableInfo)
            where T : class, new()
        {
            int length = tableInfo.Columns.Count;
            Util.ThrowIf<T>(length == 0, ErrorMessages.NO_COLUMNS);
            StringBuilder builder = new StringBuilder(Syntax.CREATE_TABLE);
            syntaxProvider.AppendTable(builder, tableInfo);
            builder.Append(" (");
            for (int i = 0; i < length; i++)
            {
                syntaxProvider.AppendCreateColumn(builder, tableInfo.Columns[i]);
                if (i != length - 1)
                {
                    builder.Append(Syntax.COMMA);
                }
            }
            syntaxProvider.AppendPrimaryKeys(builder, tableInfo);
            builder.Append(")");
            return builder.ToString();
        }

        public static string BuildDropTable<T>(ISyntaxProvider provider, TableInfo tableInfo)
            where T : class, new()
        {
            StringBuilder builder = new StringBuilder(Syntax.DROP_TABLE);
            provider.AppendTable(builder, tableInfo);
            return builder.ToString();
        }
    }
}
